package handler

import (
	"regexp"
	"server/framework/web/context"
	"server/framework/web/middleware"
)

type nodeType int

// 如下顺序为优先级顺序
const (
	nodeTypeStatic nodeType = iota // /a/b
	nodeTypeReg                    // /a/[0-9]
	nodeTypeAny                    // /a/* 支持匹配多级动态路由，比如：/a/* 可匹配/a/b/c /a/b
	nodeTypeParam                  // /a/:id 支持匹配单个路由段，比如：/a/:id 可匹配 /a/b，不可匹配/a/b/c；/:id常作为参数字段使用
)

type Node struct {
	pattern    string                                        // 当前url.path
	path       string                                        // 命中路由
	Match      func(c *context.Context, pattern string) bool // 是否命中
	nodeType   nodeType                                      // 节点类型
	children   []*Node                                       // 孩子节点
	handleFunc middleware.HandleFunc
}

func NewStaticNode(path string) *Node {
	return &Node{
		path:     path,
		nodeType: nodeTypeStatic,
		children: make([]*Node, 0),
		Match: func(c *context.Context, pattern string) bool {
			if pattern == path {
				if c != nil {
					c.MatchRoute = path
				}
				return true
			} else {
				return false
			}
		},
	}
}

func NewParamNode(path string) *Node {
	return &Node{
		path:     path, // 比如 :id
		nodeType: nodeTypeParam,
		children: make([]*Node, 0),
		Match: func(c *context.Context, pattern string) bool {
			if pattern != "*" {
				// tree 在路由注册时不存在上下文信息，c为nil
				// tree 在serveHTTP 调用时，存在上下文信息
				if c != nil {
					if c.RouteParams == nil {
						c.RouteParams = make(map[string]string)
					}
					c.RouteParams[path] = pattern
				}
				c.MatchRoute = path
				return true
			} else {
				return false
			}
		},
	}
}

func NewRegNode(path string) *Node {
	return &Node{
		path:     path,
		nodeType: nodeTypeReg,
		children: make([]*Node, 0),
		Match: func(c *context.Context, pattern string) bool {
			// 对正则进行预编译
			reg := regexp.MustCompile(path)
			if reg.MatchString(pattern) {
				if c != nil {
					c.MatchRoute = path
				}
				return true
			} else {
				return false
			}
		},
	}
}

func NewAnyNode(path string) *Node {
	return &Node{
		path:     path,
		nodeType: nodeTypeAny,
		Match: func(c *context.Context, pattern string) bool {
			if c != nil {
				c.RouteDynamic = pattern
				c.MatchRoute = path
			}

			return true
		},
	}
}
